package com.pi.nbcenter.base.task.handler;

import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.Date;
import java.util.Objects;
import java.util.TimeZone;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.pi.base.enumerate.redis.RedisCacheEnum;
import com.pi.base.util.cache.RedisUtil;
import com.pi.base.util.time.DateTools;
import com.pi.common.http.task.Processable;
import com.pi.iot.repository.constants.AlarmTypeEnum;
import com.pi.iot.repository.constants.lock.PiLockTypeEnum;
import com.pi.iot.repository.huawei.bean.notify.HuaWeiIotRecord;
import com.pi.iot.repository.huawei.constants.CommandResultCode;
import com.pi.iot.repository.huawei.constants.IotLockState;
import com.pi.iot.repository.huawei.constants.NotifyType;
import com.pi.nbcenter.base.constants.IotConstants;
import com.pi.nbcenter.base.constants.OnlineStatus;
import com.pi.nbcenter.base.constants.iot.IotService;
import com.pi.nbcenter.base.task.handler.param.DeviceInsWakeUpParam;
import com.pi.nbcenter.device.bean.dto.nb.iotservice.ServiceBatteryInfo;
import com.pi.nbcenter.device.bean.dto.nb.iotservice.ServiceLock;
import com.pi.nbcenter.device.bean.dto.nb.iotservice.ServiceSignalInfo;
import com.pi.nbcenter.device.bean.dto.session.IotSession;
import com.pi.nbcenter.device.entity.auto.IotDeviceInfo;
import com.pi.nbcenter.device.entity.auto.IotDeviceSession;
import com.pi.nbcenter.device.service.partner.BasePartnerSubscriptionService;
import com.pi.nbcenter.device.service.pi.internal.IotDeviceNotificationLogService;
import com.pi.nbcenter.device.service.pi.internal.PiIotDevService;

@Service("huaWeiIotRecordTask")
public class HuaWeiIotRecordTask implements Processable<HuaWeiIotRecord> {
  private static final Logger logger = LoggerFactory.getLogger(HuaWeiIotRecordTask.class);
  
  @Autowired
  private IotDeviceNotificationLogService notificationLogService;
  @Autowired
  private BasePartnerSubscriptionService subscriptionService;
  @Autowired
  private PiIotDevService iotDevService;
  @Autowired
  private DeviceInsExecuteTask deviceInsExecuteTask;
  
  @Override
  public void process(HuaWeiIotRecord record) {
    if(null == record || null == record.getDeviceId()){
      logger.error("通知数据为空: {}", null == record? null : JSON.toJSONString(record));
      return;
    }
    handlerNotification(record);
  }
  
  private void handlerNotification(HuaWeiIotRecord record){
    NotifyType notifyType = NotifyType.getNotifyType(record.getNotifyType());
    String commandId = record.getCommandId();
    if(null == notifyType && StringUtils.isBlank(commandId)){
      logger.error("通知类型为空-请注意： {}", JSON.toJSONString(record));
      return;
    }
    IotSession session;    
    if(null != notifyType){
      session = hanlerPlatFormNotify(notifyType, record);
    }else{
      session = new IotSession();
      session.setIotDevId(record.getDeviceId());
      handleCommandNotify(commandId, record);
    }
    updateSessionInDb(session);
  }
  
  private void handleCommandNotify(String commandId, HuaWeiIotRecord record){
    if(null == record.getResult()){
      logger.error("指令数据的result参数为空: {}.", record.toString());
      return;
    }
    CommandResultCode commandResp = record.getResult().getResultCode();
    if(null == commandResp){
      logger.error("指令数据的result参数未知: {}.", record.toString());
      return;      
    }
    //更新指令结果状态
    int code = commandResp.getCode();
  }
  private IotSession hanlerPlatFormNotify(NotifyType notifyType, HuaWeiIotRecord record){
    IotSession session = new IotSession();
    session.setIotDevId(record.getDeviceId());
    switch(notifyType){
      case SERVICE_INFO_CHANGED:
      case DEVICE_INFO_CHANGED:
      case DEVICE_ADDED:
      case DEVICE_DELETED:
      case DEVICE_EVENT:
      case RULE_EVENT:
        saveNotification(record);
        break;
      case DEVICE_DATA_CHANGED:
        handleNotifiedNotice(record);
        break;
      case DEVICE_DATAS_CHANGED:
        session = extractSessionInfo(record, session);
        DeviceInsWakeUpParam insWakeUpParam = new DeviceInsWakeUpParam();
        insWakeUpParam.setDeviceId(record.getDeviceId());
        deviceInsExecuteTask.process(insWakeUpParam);
      case MESSAGE_CONFIRM:
        handleNotifiedNotice(record);
        break;
      case COMMAND_RSP:
        handleNotifiedNotice(record);
        break;
      default:
        break;
    }
    return session;
  }
  
  public IotSession extractSessionInfo(HuaWeiIotRecord data, IotSession session){
    if(null == data || null == data.getServices() || data.getServices().size() == 0){
      return null;
    }
    JSONArray services = data.getServices();
    session = wrapSession(session);
    for(int i =0, size = services.size(); i < size; i++){
      JSONObject singleService = services.getJSONObject(i);
      IotService iotService = IotService.getIotService(singleService.getString("serviceId"));
      if(null == iotService){
        continue;
      }
      switch(iotService){
        case CONNECTIVITY:
          wrapSignl(session, singleService);
          break;
        case BATTERY:
          wrapBattery(session, singleService);
          break;
        case LOCK_STATE:
          wrapLockState(session, singleService);
          break;
        default:
          break;
      }
    }
    return session;
  }
  
  private void wrapSignl(IotSession session, JSONObject singleService){
    ServiceSignalInfo info = singleService.getObject("data", ServiceSignalInfo.class);
    //兼容新旧版本的信号强度
    if(null != info && info.getSignalStrength() == 0){
      info.setSignalStrength(singleService.getJSONObject("data").getIntValue("signalPower"));
    }
    session = wrapSession(session);
    refreshServiceTime(singleService, session);
    session.setNbRssi(info.getSignalStrength());
    if(null != info.getIMSI()){      
      session.setImsi(info.getIMSI().trim());
    }
  }
  
  private void refreshServiceTime(JSONObject service, IotSession session){
    String dateTime = service.getString("eventTime");
    if(null != dateTime){
      try {
        Date d = DateTools.parserDate(
            dateTime, "yyyyMMdd'T'HHmmss'Z'", TimeZone.getTimeZone("GMT+0:00"));
        if(null == session.getLatestActiveTime() || 
            session.getLatestActiveTime().getTime() < d.getTime()){
          session.setLatestActiveTime(d);
        }
      } catch (ParseException e) {
        logger.error("时间格式不正确:{}", dateTime);
      }
    }
  }
  private void wrapBattery(IotSession session, JSONObject singleService){
    ServiceBatteryInfo info = singleService.getObject("data", ServiceBatteryInfo.class);
    session = wrapSession(session);
    refreshServiceTime(singleService, session);
    session.setNbBattery(info.getBatteryVoltage());
    session.setBatteryLevel(info.getBatteryLevel());
    IotDeviceInfo iotDevInfo = 
        iotDevService.queryDbDeviceInfoByIotDevIdIfExist(session.getIotDevId());
    if(null != iotDevInfo 
        && PiLockTypeEnum.hasOffBatteryAlarm(iotDevInfo.getFirmwareVersion())
        && info.getBatteryState() == 0) {
      subscriptionService.sendAlarm(iotDevInfo.getIotDevId(), AlarmTypeEnum.LOCK_OFF_BATTERY, 0L);
    }
  }
  
  private void wrapLockState(IotSession session, JSONObject singleService){
    ServiceLock serviceLock = singleService.getObject("data", ServiceLock.class);
    session = wrapSession(session);
    refreshServiceTime(singleService, session);
    if(null != serviceLock.getDeviceState()){
      Object[] param = new Object[]{session.getIotDevId(),
          AlarmTypeEnum.LOCK_UNLOCK.getType()};
      if(Objects.equals(serviceLock.getDeviceState(), IotLockState.OPEN.getState())){
        session.setIotDevState(IotLockState.OPEN.getState());
        //门开启状态下需要判断是否是假锁超时
        try {
          String delayed = RedisUtil.get(RedisCacheEnum.IOT_SERVERSIDE_ALARM, param);
          if(null == delayed){
            logger.info("设备{} 假锁报警初始化", session.getIotDevId());
            RedisUtil.directset(
                RedisCacheEnum.IOT_SERVERSIDE_ALARM, String.valueOf(System.currentTimeMillis()/1000), 
                IotConstants.ALARM_CACHE_DELAY, param);
            return;
          }
          subscriptionService.sendUnlockAlarmIfNecessary(session.getIotDevId(), delayed, param);
        } catch (UnsupportedEncodingException e) {
          logger.error("",e);
        }
      }else{
        if(Objects.equals(serviceLock.getDeviceState(), IotLockState.CLOSED.getState())){
          RedisUtil.del(RedisCacheEnum.IOT_SERVERSIDE_ALARM, param);
          logger.info("{} 的假锁报警已取消", session.getIotDevId());
        }
        session.setIotDevState(IotLockState.CLOSED.getState());
      }
    }
    if(null != serviceLock.getHwVersion() || null != serviceLock.getSwVersion()){
      IotDeviceInfo iotDevInfo = 
          iotDevService.queryDbDeviceInfoByIotDevIdIfExist(session.getIotDevId());
      if(null == iotDevInfo){
        logger.error("设备{}不存在",session.getIotDevId());
        return;
      }
      boolean update = false;
      if(!iotDevInfo.getFirmwareVersion().equalsIgnoreCase(serviceLock.getHwVersion().trim())){
        update = true;
        iotDevInfo.setFirmwareVersion(serviceLock.getHwVersion().trim());
      }
        
      if(!iotDevInfo.getSoftwareVersion().equalsIgnoreCase(serviceLock.getSwVersion().trim())){
        update = true;
        iotDevInfo.setSoftwareVersion(serviceLock.getSwVersion().trim());
      }
      if(update){
        iotDevService.updateDeviceInfoById(iotDevInfo);
      }
    }
  }
  
  private IotSession wrapSession(IotSession session){
    if(null == session){
      session =  new IotSession();
    }
    return session;
  }
  
  private void saveNotification(HuaWeiIotRecord record){
    notificationLogService.addIotDeviceNotificationLog(record);
  }
  
  private void handleNotifiedNotice(HuaWeiIotRecord record){
    saveNotification(record);
    IotDeviceInfo iotDevInfo = 
        iotDevService.queryDbDeviceInfoByIotDevIdIfExist(record.getDeviceId());
    if(null != iotDevInfo){
      Integer version = iotDevInfo.getIotProtocolVersion();
      if(null == version){
        version = -1;
      }
      switch(version){
        case 200:
          logger.error("设备{}属于旧版本设备, 暂不推送订阅消息, 透传数据", record.getDeviceId());
          return;
        default:
          //查询Lock服务的lockState启动的状态或者Lock的电量或者 Message的Alarm的
          if(isServerMonitAlarm(record)){
            return;
          }
      }
      //查询设备的订阅方式并推送到url
      subscriptionService.pushToPartner(record);
    }
  }
  
  private boolean isServerMonitAlarm(HuaWeiIotRecord record) {
    if(null != record && null != record.getService()
        && "Alarm".equalsIgnoreCase(record.getService().getString("serviceType"))
        && null != record.getService().getJSONObject("data")
        //是否为正常消息
//            AlarmTypeEnum.isOK(record.getOriginData().getJSONObject("service").getJSONObject("data").getInteger("alarmType"))
        && (//            是否为假锁消息
            AlarmTypeEnum.isUnlockAlarm(record.getService().getJSONObject("data").getInteger("alarmType"))
//            是否为电量消息
            || AlarmTypeEnum.isLowBatteryAlarm(record.getService().getJSONObject("data").getInteger("alarmType")))){
      Object[] param = new Object[]{record.getDeviceId(),
          record.getService().getJSONObject("data").getInteger("alarmType")};
      //判断key是否存在
      
      try {
        if(null != param[1])
          RedisUtil.setIfNotExist(
              RedisCacheEnum.IOT_SERVERSIDE_ALARM, String.valueOf(System.currentTimeMillis()/1000), 
              IotConstants.ALARM_CACHE_DELAY, param);
      } catch (UnsupportedEncodingException e) {
        logger.error("设置缓存失败", e.getMessage());
      }
      return true;
    }
    return false;
  }
  
  
  private void updateSessionInDb(IotSession session) {
    if(null == session || StringUtils.isBlank(session.getIotDevId())) {
      return;
    }
    IotDeviceSession sessionInDb = new IotDeviceSession();
    sessionInDb.setIotDevId(session.getIotDevId());
    sessionInDb.setIotDevBattery(session.getNbBattery());
    sessionInDb.setIotDevBatteryPercent(session.getBatteryLevel());
    sessionInDb.setIotDevRssi(session.getNbRssi());
    sessionInDb.setLatestActiveTime(session.getLatestActiveTime());
    sessionInDb.setIotDevState(OnlineStatus.online.value());
    //更新在线状态
    iotDevService.updateDeviceSession(sessionInDb);
  }

}
